package caramcraft;

import java.util.LinkedList;

import math.geom2d.Vector2D;
import jnibwapi.JNIBWAPI;
import jnibwapi.model.Unit;
import jnibwapi.types.WeaponType;

public class Tank extends SCUnit {
	private WeaponType weaponTypeSiege = bwapi
			.getWeaponType(WeaponType.WeaponTypes.Arclite_Shock_Cannon.getID());
	private Tank otherTank = null;

	public Tank(Unit unit, JNIBWAPI bwapi) {
		super(unit, bwapi, bwapi
				.getWeaponType(WeaponType.WeaponTypes.Arclite_Cannon.getID()));
	}

	public Tank(Unit unit, JNIBWAPI bwapi, LinkedList<SCUnit> myUnits,
			LinkedList<Unit> myBuildings, LinkedList<SCUnit> enemyUnits,
			LinkedList<Unit> enemyBuildings) {
		super(unit, bwapi, bwapi
				.getWeaponType(WeaponType.WeaponTypes.Arclite_Cannon.getID()),
				myUnits, myBuildings, enemyUnits, enemyBuildings);
	}

	public void step(long frame) {
		if (isSleep(frame))
			return;

		if (otherTank == null)
			this.getOtherTank();

		SCUnit nearestEnemy = this.getNearestEnemy();
		if (nearestEnemy == null)
			return;

		double distanceToNearestEnemy = this.getDistance(nearestEnemy.me);
		// if enemy is in range then make sure we are sieged
		boolean siegeTankEnemy = this.enemySiegedTankInRange();
		if (!this.isSieged()
				&& ((siegeTankEnemy && distanceToNearestEnemy < this.weaponTypeSiege
						.getMaxRange()) || (!siegeTankEnemy && distanceToNearestEnemy < (this.weaponTypeSiege
						.getMaxRange() * 0.9)))) {
			this.siege();
			sleep(frame, 5);
			return;
		}
		if (this.isSieged()) {
			// if we are attacking, just continue
			if (this.isAttacking())
				return;
			// if no enemies are near then unsiege
			if (distanceToNearestEnemy > this.weaponTypeSiege.getMaxRange()) {
				this.unsiege();
				sleep(frame, 5);
				return;
			}
			// get a good target for attacking

		}
		// move to enemies
		if (nearestEnemy != null) {
			Vector2D moveTo = nearestEnemy.getPosition();
			if (otherTank != null && !otherTank.isDead()) {
				// stay on the same line
				double distance1 = getDistance(nearestEnemy.me) + 50;
				double distance2 = otherTank.getDistance(nearestEnemy.me);
				if (distance1 < distance2) {
					moveTo = getPosition().plus(
							moveTo.minus(getPosition()).opposite().normalize());
					moveTo = moveTo.plus(seperate(100));
					move(moveTo);
					sleep(frame, 2);
					return;
				}
			}
			move(nearestEnemy.me);
			sleep(frame, 2);
		}
	}

	public boolean siege() {
		return bwapi.siege(me.getID());
	}

	public boolean unsiege() {
		return bwapi.unsiege(me.getID());
	}

	public boolean isSieged() {
		return me.isSieged();
	}

	@Override
	public int getDamage() {
		if (isSieged())
			return this.weaponTypeSiege.getDamageAmount();
		else
			return this.weaponType.getDamageAmount();
	}

	public void getOtherTank() {
		for (SCUnit u : this.myUnits) {
			if (u instanceof Tank && u.getID() != me.getID()) {
				this.otherTank = (Tank) u;
				return;
			}
		}
	}

	@Override
	public Vector2D seperate(double radius) {
		Vector2D result = new Vector2D();
		if (otherTank != null && otherTank.getHealth() > 0) {
			double distance = getDistance(otherTank.getUnit());
			if (distance < radius) {
				result = result.plus(otherTank.getPosition()
						.minus(this.getPosition()).opposite());
			}
		}
		return result;
	}

	public boolean enemySiegedTankInRange() {
		for (SCUnit u : enemyUnits) {
			if (u instanceof Tank
					&& !u.isDead()
					&& ((Tank) u).isSieged()
					&& u.getDistance(this.me) <= (((Tank) u).weaponTypeSiege
							.getMaxRange() * 1.1)) {
				return true;
			}
		}
		return false;
	}

}
